/**
 * <pre>
 * @(#)ViewContainer.java 1.00 2009-11-4
 * 
 * Copyright (c) 1998, 2009 Regular Individual. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Contributor(s):
 *     Haixu Huang
 * </pre>
 **/
package cn.sh.huang.chart.view.container;

import java.awt.AWTEventMulticaster;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.EventListener;

import cn.sh.huang.chart.ext.MouseEventListener;
import cn.sh.huang.chart.view.AbstractView;
import cn.sh.huang.chart.view.View;

/**
 * <pre>
 * ViewContainer ...
 * 
 * @version 1.0
 * </pre>
 */
public abstract class ViewContainer extends View implements Container
{
    final public Rectangle getViewRect(AbstractView view)
    {
        Rectangle gridRect = getGridRect(view); // view's gridRect
        Point shift = getViewShift(); // container's accumulated shift
        gridRect.translate(shift.x, shift.y); // view's absolute rect

        /**
         * <code> +---+ x = 2
         * anchor v   v
         *     +->+-----------+-----------+
         *     |  |           |           |
         *   y = 4|           |  gridRect |
         *     |  |           |           |
         *     +->|   +-------+------+    |
         *        |   |       |######|    |
         *        |   |       +------+----+
         *        |   |              |    |
         *        |   |   viewRect   |    |
         *        +---+--------------+----+
         * </code>
         */
        Rectangle viewRect = getViewRect(); // container's visibleRect(absolute)
        Rectangle inter = gridRect.intersection(viewRect); // intersection
        inter.width = Math.max(inter.width, 0); // Really don't like negative number
        inter.height = Math.max(inter.height, 0);
        return inter;
    }

    public void mouseClicked(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mouseDragged(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mouseExited(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mouseMoved(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mousePressed(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mouseReleased(MouseEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public void mouseWheelMoved(MouseWheelEvent e)
    {
        dispatchViewMouseEvent(e);
    }

    public synchronized void removeMouseEventListener(MouseEventListener l)
    {
        if (l == null) {
            return;
        }
        mouseEventListener = ChartEventMulticaster.remove(mouseEventListener, l);
    }

    private void dispatchViewMouseEvent(MouseEvent e)
    {
        MouseEventListener[] listeners = getMouseEventListeners();
        for (int i = 0; i < listeners.length; i++) {
            if (listeners[i] instanceof AbstractView) {
                AbstractView view = (AbstractView) listeners[i];
                Rectangle subViewRect = getViewRect(view);
                if (subViewRect.width <= 0 || subViewRect.height <= 0) {
                    continue;
                }
                int eid = e.getID();
                if (eid == MouseEvent.MOUSE_DRAGGED || eid == MouseEvent.MOUSE_RELEASED
                    || subViewRect.contains(e.getPoint())) {
                    view.processMouseEvent(e);
                }
            }
        }
    }

    private transient MouseEventListener mouseEventListener = null;

    public synchronized void addMouseEventListener(MouseEventListener l)
    {
        if (l == null) {
            return;
        }
        mouseEventListener = ChartEventMulticaster.add(mouseEventListener, l);
    }

    private synchronized MouseEventListener[] getMouseEventListeners()
    {
        return (MouseEventListener[]) ChartEventMulticaster.getListeners(mouseEventListener, MouseEventListener.class);
    }
}

class ChartEventMulticaster extends AWTEventMulticaster implements MouseEventListener
{
    public static MouseEventListener add(MouseEventListener a, MouseEventListener b)
    {
        return (MouseEventListener) addInternal(a, b);
    }

    public static MouseEventListener remove(MouseEventListener l, MouseEventListener oldl)
    {
        return (MouseEventListener) removeInternal(l, oldl);
    }

    protected static EventListener addInternal(EventListener a, EventListener b)
    {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return new ChartEventMulticaster(a, b);
    }

    protected ChartEventMulticaster(EventListener a, EventListener b)
    {
        super(a, b);
    }
}
